/*****************************************************************************
 * Copyright (c) 2024, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
 * @file: nss32lbx_qflash.c
 * @author Nations Firmware Team
 * @copyright: Copyright (c) 2024, Nations Technologies Inc. All rights reserved.
 * @brief:
 *
 * @history:
 *    Date			Version		Changes
 *    2024-04-12	1.0.0		init
 *    2024-04-23	1.0.1       add chip erase cmd
 *    2024-05-31    1.0.2       fix read instruction In some scenarios, the end data is abnormal
 *    2024-06-24    1.0.3       Extend the command timeout waiting time
 *    2024-06-28    1.0.4       Modify OTP interface parameters
 */

#include "nss32lbx_qflash.h"
#include <string.h>
/** @addtogroup nss32lbx_StdPeriph_Driver
 * @{
 */

/** @addtogroup QFLASH
 * @brief QFLASH driver modules
 * @{
 */

/** @addtogroup QFLASH_Private_TypesDefinitions
 * @{
 */

/**
 * @}
 */

/** @addtogroup QFLASH_Private_Defines
 * @{
 */

#define GLOBAL_INT_DISABLE()             \
    uint32_t ui32IntStatus = 0;          \
    do                                   \
    {                                    \
        ui32IntStatus = __get_PRIMASK(); \
        __set_PRIMASK(1);                \
    } while (0)

#define GLOBAL_INT_RESTORE()          \
    do                                \
    {                                 \
        __set_PRIMASK(ui32IntStatus); \
    } while (0)

/**
 * @}
 */

/** @addtogroup QFLASH_Private_Macros
 * @{
 */

/**
 * @}
 */

/** @addtogroup QFLASH_Private_Variables
 * @{
 */
#define EWR_CMD_CODE_LEN 0x3c0
#define EWR_CMD_CODE_CRC 0xdbea

static uint32_t ram_ewr_cmd_code[EWR_CMD_CODE_LEN / 4 + 1];

const unsigned char ewr_cmd_code[] = {
    0x01, 0x38, 0xfd, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x01, 0x23, 0x5b, 0x05, 0x98, 0x42, 0x01, 0xd9, 0x05, 0x20, 0x70,
    0x47, 0xf0, 0xb4, 0x84, 0x46, 0x03, 0x20, 0x80, 0x06, 0x03, 0x6a, 0x5b, 0x08, 0x5b, 0x00, 0x03, 0x62, 0x03, 0x6a,
    0x02, 0x24, 0x23, 0x43, 0x03, 0x62, 0x03, 0x6a, 0x9b, 0x07, 0xfc, 0xd4, 0xff, 0x24, 0x01, 0x34, 0x84, 0x62, 0x00,
    0x23, 0x01, 0x27, 0x03, 0x24, 0xa4, 0x06, 0xe7, 0x60, 0x35, 0x20, 0x60, 0x60, 0x27, 0x61, 0xa0, 0x6a, 0xc0, 0x05,
    0xfc, 0xd5, 0xff, 0x20, 0x01, 0x30, 0xa0, 0x62, 0xa5, 0x69, 0xe7, 0x60, 0xed, 0xb2, 0x05, 0x26, 0x66, 0x60, 0x27,
    0x61, 0xa6, 0x6a, 0xf6, 0x05, 0xfc, 0xd5, 0xa0, 0x62, 0xa4, 0x69, 0x28, 0x02, 0x20, 0x43, 0xc0, 0x07, 0x04, 0xd0,
    0xd0, 0x48, 0x83, 0x42, 0x4a, 0xd8, 0x5b, 0x1c, 0xdf, 0xe7, 0x03, 0x20, 0x80, 0x06, 0x43, 0x69, 0xff, 0x24, 0x08,
    0x34, 0xa3, 0x43, 0x43, 0x61, 0x43, 0x69, 0xe4, 0x1e, 0x23, 0x43, 0x43, 0x61, 0x63, 0x46, 0x1b, 0x02, 0x6b, 0x33,
    0x43, 0x60, 0x08, 0x23, 0x83, 0x60, 0xc2, 0x60, 0x07, 0x61, 0x83, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0xff, 0x23, 0x01,
    0x33, 0x83, 0x62, 0x00, 0x20, 0x93, 0x08, 0x0e, 0xd0, 0x95, 0x08, 0xc0, 0x4b, 0x1b, 0x68, 0x84, 0x00, 0x0b, 0x55,
    0x1e, 0x0a, 0x64, 0x18, 0x66, 0x70, 0x1e, 0x0c, 0x1b, 0x0e, 0xa6, 0x70, 0x40, 0x1c, 0xe3, 0x70, 0x85, 0x42, 0xf1,
    0xd8, 0x93, 0x07, 0x1b, 0xd0, 0xb8, 0x4b, 0x1b, 0x68, 0x94, 0x07, 0xa4, 0x0f, 0x01, 0x2c, 0x05, 0xd0, 0x02, 0x2c,
    0x06, 0xd0, 0xd2, 0x43, 0x92, 0x07, 0x09, 0xd0, 0x0f, 0xe0, 0x80, 0x00, 0x0b, 0x54, 0x0c, 0xe0, 0x80, 0x00, 0x0b,
    0x54, 0x1a, 0x0a, 0x40, 0x18, 0x42, 0x70, 0x06, 0xe0, 0x80, 0x00, 0x0b, 0x54, 0x1a, 0x0a, 0x40, 0x18, 0x42, 0x70,
    0x19, 0x0c, 0x81, 0x70, 0x03, 0x20, 0x80, 0x06, 0x41, 0x69, 0xff, 0x22, 0x08, 0x32, 0x91, 0x43, 0x41, 0x61, 0x41,
    0x69, 0x39, 0x43, 0x41, 0x61, 0x01, 0x6a, 0x89, 0x08, 0x89, 0x00, 0x01, 0x62, 0x01, 0x6a, 0x39, 0x43, 0x01, 0x62,
    0xf0, 0xbc, 0x00, 0x20, 0x70, 0x47, 0xf0, 0xb4, 0x03, 0x46, 0x01, 0x21, 0x00, 0x20, 0x49, 0x05, 0x8b, 0x42, 0x02,
    0xd9, 0xf0, 0xbc, 0x05, 0x20, 0x70, 0x47, 0x03, 0x22, 0x92, 0x06, 0x11, 0x6a, 0x49, 0x08, 0x49, 0x00, 0x11, 0x62,
    0x11, 0x6a, 0x02, 0x24, 0x21, 0x43, 0x11, 0x62, 0x11, 0x6a, 0x89, 0x07, 0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x96,
    0x62, 0x01, 0x25, 0xd5, 0x60, 0x35, 0x21, 0x51, 0x60, 0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62,
    0x91, 0x69, 0xd5, 0x60, 0xc9, 0xb2, 0x05, 0x24, 0x54, 0x60, 0x15, 0x61, 0x97, 0x6a, 0xff, 0x05, 0xfc, 0xd5, 0x96,
    0x62, 0x97, 0x69, 0x09, 0x02, 0x39, 0x43, 0xc9, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x29, 0xe0, 0x06, 0x21, 0x51, 0x60,
    0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x19, 0x02, 0x20, 0x31, 0x51, 0x60, 0x15, 0x61, 0x91,
    0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x00, 0x21, 0xd5, 0x60, 0x35, 0x23, 0x53, 0x60, 0x15, 0x61, 0x93, 0x6a,
    0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x93, 0x69, 0xd5, 0x60, 0xdb, 0xb2, 0x54, 0x60, 0x15, 0x61, 0x97, 0x6a, 0xff,
    0x05, 0xfc, 0xd5, 0x96, 0x62, 0x97, 0x69, 0x1b, 0x02, 0x3b, 0x43, 0xdb, 0x07, 0x03, 0xd0, 0x74, 0x4b, 0x99, 0x42,
    0x11, 0xd9, 0x02, 0x20, 0x51, 0x69, 0xff, 0x23, 0x08, 0x33, 0x99, 0x43, 0x51, 0x61, 0x51, 0x69, 0x29, 0x43, 0x51,
    0x61, 0x11, 0x6a, 0x89, 0x08, 0x89, 0x00, 0x11, 0x62, 0x11, 0x6a, 0x29, 0x43, 0x11, 0x62, 0xf0, 0xbc, 0x70, 0x47,
    0x49, 0x1c, 0xd2, 0xe7, 0xf7, 0xb5, 0x81, 0xb0, 0x00, 0x21, 0x00, 0x91, 0x01, 0x21, 0x49, 0x05, 0x88, 0x42, 0x02,
    0xd9, 0x05, 0x20, 0x04, 0xb0, 0xf0, 0xbd, 0x03, 0x21, 0x89, 0x06, 0x0b, 0x6a, 0x5b, 0x08, 0x5b, 0x00, 0x0b, 0x62,
    0x0b, 0x6a, 0x02, 0x24, 0x23, 0x43, 0x0b, 0x62, 0x0b, 0x6a, 0x9b, 0x07, 0xfc, 0xd4, 0xff, 0x25, 0x01, 0x35, 0x8d,
    0x62, 0x01, 0x24, 0xcc, 0x60, 0x35, 0x27, 0x4f, 0x60, 0x0c, 0x61, 0x8b, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0x8d, 0x62,
    0x8b, 0x69, 0x01, 0x26, 0xdb, 0xb2, 0xce, 0x60, 0x05, 0x24, 0x4c, 0x60, 0x0e, 0x61, 0x8e, 0x6a, 0xf6, 0x05, 0xfc,
    0xd5, 0x03, 0x26, 0xb6, 0x06, 0xb5, 0x62, 0x19, 0x02, 0xb3, 0x69, 0x19, 0x43, 0xc9, 0x07, 0x01, 0xd0, 0x03, 0x20,
    0x70, 0xe0, 0x00, 0x21, 0x8c, 0x46, 0x00, 0x2a, 0x7b, 0xd0, 0x02, 0x9b, 0x11, 0x04, 0x63, 0x44, 0x9e, 0x46, 0x09,
    0x0e, 0x03, 0x06, 0x1b, 0x0e, 0x66, 0xd0, 0xff, 0x21, 0xc3, 0xb2, 0x01, 0x31, 0xcb, 0x1a, 0x9a, 0x42, 0x00, 0xd8,
    0x13, 0x46, 0x06, 0x24, 0x61, 0x06, 0x4c, 0x60, 0x01, 0x24, 0x0c, 0x61, 0x8c, 0x6a, 0xe4, 0x05, 0xfc, 0xd5, 0xff,
    0x24, 0x01, 0x34, 0x03, 0x21, 0x89, 0x06, 0x8c, 0x62, 0x4c, 0x69, 0xff, 0x25, 0x08, 0x35, 0xac, 0x43, 0x4c, 0x61,
    0x4c, 0x69, 0x04, 0x25, 0x2c, 0x43, 0x4c, 0x61, 0x04, 0x02, 0x32, 0x34, 0x4c, 0x60, 0xcb, 0x60, 0x00, 0x25, 0x00,
    0x2b, 0x16, 0xd9, 0x71, 0x46, 0x4f, 0x19, 0x3e, 0x78, 0xfc, 0x78, 0x31, 0x46, 0x7e, 0x78, 0x24, 0x06, 0x36, 0x02,
    0x31, 0x43, 0xbe, 0x78, 0x36, 0x04, 0x31, 0x43, 0x21, 0x43, 0x09, 0x02, 0xfc, 0x78, 0x09, 0x0a, 0x24, 0x06, 0x21,
    0x43, 0x2a, 0x4c, 0x21, 0x60, 0x2d, 0x1d, 0x9d, 0x42, 0xe8, 0xd3, 0x01, 0x26, 0x03, 0x24, 0xa4, 0x06, 0x26, 0x61,
    0xa1, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0xff, 0x25, 0x01, 0x35, 0xa5, 0x62, 0x00, 0x21, 0xe6, 0x60, 0x35, 0x25, 0x65,
    0x60, 0x26, 0x61, 0xa5, 0x6a, 0xed, 0x05, 0xfc, 0xd5, 0xff, 0x25, 0x01, 0x35, 0xa5, 0x62, 0xa5, 0x69, 0xe6, 0x60,
    0xed, 0xb2, 0x05, 0x27, 0x67, 0x60, 0x26, 0x61, 0xa7, 0x6a, 0xff, 0x05, 0xfc, 0xd5, 0xff, 0x27, 0x01, 0x37, 0xa7,
    0x62, 0xa7, 0x69, 0x2d, 0x02, 0x3d, 0x43, 0xed, 0x07, 0x0c, 0xd0, 0x14, 0x4d, 0xa9, 0x42, 0x07, 0xd9, 0x02, 0x20,
    0x00, 0x90, 0x0c, 0xe0, 0x00, 0x29, 0x9c, 0xd0, 0xff, 0x23, 0x01, 0x33, 0x9a, 0xe7, 0x49, 0x1c, 0xd7, 0xe7, 0x61,
    0x46, 0xc9, 0x18, 0xc0, 0x18, 0x8c, 0x46, 0xd2, 0x1a, 0x83, 0xd1, 0x03, 0x20, 0x80, 0x06, 0x41, 0x69, 0xff, 0x22,
    0x08, 0x32, 0x91, 0x43, 0x41, 0x61, 0x41, 0x69, 0x01, 0x22, 0x11, 0x43, 0x41, 0x61, 0x01, 0x6a, 0x89, 0x08, 0x89,
    0x00, 0x01, 0x62, 0x01, 0x6a, 0x11, 0x43, 0x01, 0x62, 0x00, 0x98, 0x04, 0xb0, 0xf0, 0xbd, 0x00, 0x00, 0x09, 0x3d,
    0x00, 0x00, 0x80, 0x00, 0x00, 0x0c, 0x81, 0xf2, 0x07, 0x00,
};

/**
 * @}
 */

/** @addtogroup QFLASH_Private_FunctionPrototypes
 * @{
 */
typedef ReturnMsg CMD_FLASH_SE_t(uint32_t flash_address);
typedef ReturnMsg CMD_FLASH_WR_t(uint32_t flash_address, uint8_t *p_data, uint32_t len);
typedef ReturnMsg CMD_FLASH_RD_t(uint32_t flash_address, uint8_t *p_data, uint32_t len);

ReturnMsg (*CMD_QFLASH_SE)(uint32_t flash_address);
ReturnMsg (*CMD_QFLASH_WR)(uint32_t addr, uint8_t *p_data, uint32_t len);
ReturnMsg (*CMD_QFLASH_RD)(uint32_t addr, uint8_t *p_data, uint32_t len);

/**
 * @}
 */

/** @addtogroup QFLASH_Private_Functions
 * @{
 */

/**
 * @brief  Initialize Qflash.
 */
void Qflash_Init(void)
{
    //Init Qflash algorithm
    CMD_QFLASH_RD = (CMD_FLASH_RD_t *)((uint8_t *)ram_ewr_cmd_code + 0x09);
    CMD_QFLASH_SE = (CMD_FLASH_SE_t *)((uint8_t *)ram_ewr_cmd_code + 0x137);
    CMD_QFLASH_WR = (CMD_FLASH_WR_t *)((uint8_t *)ram_ewr_cmd_code + 0x219);
    memcpy(ram_ewr_cmd_code, ewr_cmd_code, EWR_CMD_CODE_LEN);
}

/**
 * @brief Erase one sector in flash with ble schedule on.
 * @param[in] flash_address erase address.
 * @return ReturnMsg.
 */
uint32_t Qflash_Erase_Sector(uint32_t address)
{
    ReturnMsg error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    address -= 0x01000000;
    assert_param(CMD_QFLASH_SE != NULL);
    if (ADDRESS_CHECK(address))
    {
        error = CMD_QFLASH_SE(address);
    }
    assert_param(error == FlashOperationSuccess);
    GLOBAL_INT_RESTORE();
    return error;
}

/**
 * @brief Write mutable length data to flash with ble schedule on.
 * @param[in] addr flash address.
 * @param[in] p_data data to write.
 * @param[in] len data len.
 * @return ReturnMsg.
 */
uint32_t Qflash_Write(uint32_t address, uint8_t *p_data, uint32_t len)
{
    ReturnMsg error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    address -= 0x01000000;
    assert_param(CMD_QFLASH_WR != NULL);
    if (ADDRESS_CHECK(address))
    {
        error = CMD_QFLASH_WR(address, p_data, len);
    }
    assert_param(error == FlashOperationSuccess);
    GLOBAL_INT_RESTORE();
    return error;
}

/**
 * @brief Read mutable length data to ram.
 * @param[in] addr flash address.
 * @param[out] p_data data to read.
 * @param[in] len data len.
 * @return ReturnMsg.
 */
uint32_t Qflash_Read(uint32_t address, uint8_t *p_data, uint32_t len)
{
    ReturnMsg error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    address -= 0x01000000;
    assert_param(CMD_QFLASH_RD != NULL);
    if (ADDRESS_CHECK(address))
    {
        error = CMD_QFLASH_RD(address, p_data, len);
    }
    assert_param(error == FlashOperationSuccess);
    GLOBAL_INT_RESTORE();
    return error;
}

#ifdef USE_OTP_TRIM

//Read UID
typedef ReturnMsg (*ruid_cmd_func_t)(uint8_t *Identification);
#define RUID_CMD_CODE_LEN 0xc8
#define RUID_CMD_CODE_CRC 0x9936

const unsigned char ruid_cmd_code[] = {
    0xf0, 0xb4, 0x00, 0x24, 0x03, 0x25, 0xad, 0x06, 0x29, 0x6a, 0x49, 0x08, 0x49, 0x00, 0x29, 0x62, 0x29, 0x6a, 0x02,
    0x22, 0x11, 0x43, 0x29, 0x62, 0x29, 0x6a, 0x89, 0x07, 0xfc, 0xd4, 0xff, 0x23, 0x01, 0x33, 0xab, 0x62, 0x01, 0x26,
    0xee, 0x60, 0x35, 0x21, 0x69, 0x60, 0x2e, 0x61, 0xa9, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0xab, 0x62, 0xa9, 0x69, 0xee,
    0x60, 0xca, 0xb2, 0x05, 0x21, 0x69, 0x60, 0x2e, 0x61, 0xa9, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0xab, 0x62, 0x11, 0x02,
    0xaa, 0x69, 0x11, 0x43, 0xc9, 0x07, 0x01, 0xd0, 0x03, 0x24, 0x23, 0xe0, 0x6a, 0x69, 0xff, 0x21, 0x08, 0x31, 0x8a,
    0x43, 0x6a, 0x61, 0x69, 0x69, 0xff, 0x22, 0x05, 0x32, 0x11, 0x43, 0x69, 0x61, 0x4b, 0x21, 0x69, 0x60, 0x20, 0x21,
    0xa9, 0x60, 0x10, 0x21, 0xe9, 0x60, 0x2e, 0x61, 0xa9, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0xab, 0x62, 0x00, 0x22, 0x0f,
    0x49, 0x09, 0x68, 0x93, 0x00, 0xc1, 0x54, 0x0f, 0x0a, 0x1b, 0x18, 0x5f, 0x70, 0x0f, 0x0c, 0x09, 0x0e, 0x9f, 0x70,
    0x52, 0x1c, 0xd9, 0x70, 0x04, 0x2a, 0xf1, 0xd3, 0x69, 0x69, 0xff, 0x20, 0x08, 0x30, 0x81, 0x43, 0x69, 0x61, 0x68,
    0x69, 0x30, 0x43, 0x68, 0x61, 0x28, 0x6a, 0x80, 0x08, 0x80, 0x00, 0x28, 0x62, 0x28, 0x6a, 0x30, 0x43, 0x28, 0x62,
    0x20, 0x46, 0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x00, 0x0c,
};

/**
 * @brief Read Flash UUID
 * @param[out] 16Byte UUID.
 * @return ReturnMsg.
 */
uint32_t Qflash_RUID(uint8_t *Identification)
{
    uint32_t error = FlashIsBusy;
    GLOBAL_INT_DISABLE();
    uint32_t ramcode[RUID_CMD_CODE_LEN / 4 + 1];
    ruid_cmd_func_t ruid_cmd_func = (ruid_cmd_func_t)((uint8_t *)&ramcode[0] + 0x01);
    memcpy((void *)ramcode, (const void *)ruid_cmd_code, RUID_CMD_CODE_LEN);
    error = (*ruid_cmd_func)(Identification);
    GLOBAL_INT_RESTORE();
    return error;
}

// Read OTP
typedef ReturnMsg (*otp_rd_cmd_func_t)(uint32_t addr, uint8_t *p_data, uint32_t len);

#define OTP_RD_CMD_CODE_LEN 0x138
#define OTP_RD_CMD_CODE_CRC 0xcec4

const unsigned char otp_rd_cmd_code[] = {
    0x01, 0x38, 0xfd, 0xd1, 0x70, 0x47, 0x00, 0x00, 0xf0, 0xb4, 0x84, 0x46, 0x00, 0x20, 0x03, 0x23, 0x9b, 0x06, 0x1c,
    0x6a, 0x64, 0x08, 0x64, 0x00, 0x1c, 0x62, 0x1c, 0x6a, 0x02, 0x25, 0x2c, 0x43, 0x1c, 0x62, 0x1c, 0x6a, 0xa4, 0x07,
    0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x9e, 0x62, 0x01, 0x25, 0xdd, 0x60, 0x35, 0x24, 0x5c, 0x60, 0x1d, 0x61, 0x9c,
    0x6a, 0xe4, 0x05, 0xfc, 0xd5, 0x9e, 0x62, 0x9c, 0x69, 0x01, 0x27, 0xe4, 0xb2, 0xdf, 0x60, 0x05, 0x25, 0x5d, 0x60,
    0x1f, 0x61, 0x9d, 0x6a, 0xed, 0x05, 0xfc, 0xd5, 0x03, 0x25, 0xad, 0x06, 0xae, 0x62, 0x23, 0x02, 0xac, 0x69, 0x23,
    0x43, 0xdb, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x51, 0xe0, 0x03, 0x23, 0x9b, 0x06, 0x5d, 0x69, 0xff, 0x24, 0x08, 0x34,
    0xa5, 0x43, 0x5d, 0x61, 0x5c, 0x69, 0xff, 0x25, 0x05, 0x35, 0x2c, 0x43, 0x5c, 0x61, 0x64, 0x46, 0x24, 0x02, 0x48,
    0x34, 0x5c, 0x60, 0x08, 0x24, 0x9c, 0x60, 0xda, 0x60, 0x01, 0x24, 0x1c, 0x61, 0x9c, 0x6a, 0xe4, 0x05, 0xfc, 0xd5,
    0xff, 0x24, 0x01, 0x34, 0x03, 0x23, 0x9b, 0x06, 0x9c, 0x62, 0x00, 0x23, 0x94, 0x08, 0x0e, 0xd0, 0x96, 0x08, 0x22,
    0x4c, 0x24, 0x68, 0x9d, 0x00, 0x4c, 0x55, 0x27, 0x0a, 0x6d, 0x18, 0x6f, 0x70, 0x27, 0x0c, 0x24, 0x0e, 0xaf, 0x70,
    0x5b, 0x1c, 0xec, 0x70, 0x9e, 0x42, 0xf1, 0xd8, 0x94, 0x07, 0x1b, 0xd0, 0x1a, 0x4c, 0x24, 0x68, 0x95, 0x07, 0xad,
    0x0f, 0x01, 0x2d, 0x05, 0xd0, 0x02, 0x2d, 0x06, 0xd0, 0xd2, 0x43, 0x92, 0x07, 0x09, 0xd0, 0x0f, 0xe0, 0x9a, 0x00,
    0x8c, 0x54, 0x0c, 0xe0, 0x9a, 0x00, 0x8c, 0x54, 0x23, 0x0a, 0x51, 0x18, 0x4b, 0x70, 0x06, 0xe0, 0x9a, 0x00, 0x8c,
    0x54, 0x23, 0x0a, 0x51, 0x18, 0x4b, 0x70, 0x22, 0x0c, 0x8a, 0x70, 0xff, 0x21, 0x01, 0x31, 0x03, 0x22, 0x92, 0x06,
    0x91, 0x62, 0x03, 0x21, 0x89, 0x06, 0x4b, 0x69, 0xff, 0x22, 0x08, 0x32, 0x93, 0x43, 0x4b, 0x61, 0x4b, 0x69, 0x01,
    0x22, 0x13, 0x43, 0x4b, 0x61, 0x0b, 0x6a, 0x9b, 0x08, 0x9b, 0x00, 0x0b, 0x62, 0x0b, 0x6a, 0x13, 0x43, 0x0b, 0x62,
    0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x00, 0x0c,
};

/**
 * @brief Read mutable length data to ram.
 * @param[in] addr Security Registers Address.
 * @param[out] p_data data to read.
 * @param[in] len data len.256Byte max
 * @return ReturnMsg.
 */
uint32_t OTPTrim_Read(uint32_t addr, uint8_t *p_data, uint32_t len)
{
    uint32_t error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    if (OTP_ADDRESS_CHECK(addr))
    {
        uint32_t ramcode[OTP_RD_CMD_CODE_LEN / 4 + 1];
        otp_rd_cmd_func_t otp_read_cmd_func = (otp_rd_cmd_func_t)((uint8_t *)&ramcode[0] + 0x09);
        memcpy((void *)ramcode, (const void *)otp_rd_cmd_code, OTP_RD_CMD_CODE_LEN);
        error = (*otp_read_cmd_func)(addr, p_data, len);
    }
    GLOBAL_INT_RESTORE();
    return error;
}

// Erase OTP
typedef ReturnMsg (*otp_se_cmd_func_t)(uint32_t addr);

#define OTP_SE_CMD_CODE_LEN 0xe0
#define OTP_SE_CMD_CODE_CRC 0x2425

const unsigned char otp_se_cmd_code[] = {
    0xf0, 0xb4, 0x84, 0x46, 0x00, 0x20, 0x03, 0x22, 0x92, 0x06, 0x11, 0x6a, 0x49, 0x08, 0x49, 0x00, 0x11, 0x62, 0x11,
    0x6a, 0x02, 0x23, 0x19, 0x43, 0x11, 0x62, 0x11, 0x6a, 0x89, 0x07, 0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x96, 0x62,
    0x01, 0x25, 0xd5, 0x60, 0x35, 0x27, 0x57, 0x60, 0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x91,
    0x69, 0xd5, 0x60, 0xcc, 0xb2, 0x05, 0x23, 0x53, 0x60, 0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62,
    0x91, 0x69, 0x24, 0x02, 0x0c, 0x43, 0xe1, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x2f, 0xe0, 0x06, 0x24, 0x54, 0x60, 0x15,
    0x61, 0x94, 0x6a, 0xe4, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x61, 0x46, 0x09, 0x02, 0x44, 0x31, 0x51, 0x60, 0x15, 0x61,
    0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x00, 0x21, 0x1f, 0x46, 0xd5, 0x60, 0x35, 0x23, 0x53, 0x60, 0x15,
    0x61, 0x93, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x93, 0x69, 0xd5, 0x60, 0xdb, 0xb2, 0x57, 0x60, 0x15, 0x61,
    0x94, 0x6a, 0xe4, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x94, 0x69, 0x1b, 0x02, 0x23, 0x43, 0xdb, 0x07, 0x06, 0xd0, 0x0c,
    0x4b, 0x99, 0x42, 0x01, 0xd9, 0x02, 0x20, 0x02, 0xe0, 0x49, 0x1c, 0xe2, 0xe7, 0x96, 0x62, 0x51, 0x69, 0xff, 0x23,
    0x08, 0x33, 0x99, 0x43, 0x51, 0x61, 0x51, 0x69, 0x29, 0x43, 0x51, 0x61, 0x11, 0x6a, 0x89, 0x08, 0x89, 0x00, 0x11,
    0x62, 0x11, 0x6a, 0x29, 0x43, 0x11, 0x62, 0xf0, 0xbc, 0x70, 0x47, 0x81, 0xf2, 0x07, 0x00,
};

/**
 * @brief Erase Security Registers.
 * @param[in] addr Security Registers Address.
 * @return ReturnMsg.
 */
uint32_t OTPTrim_Erase(uint32_t addr)
{
    uint32_t error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    if (OTP_ADDRESS_CHECK(addr))
    {
        uint32_t ramcode[OTP_SE_CMD_CODE_LEN / 4 + 1];
        otp_se_cmd_func_t otp_erase_cmd_func = (otp_se_cmd_func_t)((uint8_t *)&ramcode[0] + 0x01);
        memcpy((void *)ramcode, (const void *)otp_se_cmd_code, OTP_SE_CMD_CODE_LEN);
        error = (*otp_erase_cmd_func)(addr);
    }
    GLOBAL_INT_RESTORE();
    return error;
}

// Write OTP
typedef ReturnMsg (*otp_wr_cmd_func_t)(uint32_t addr, uint8_t *p_data, uint32_t len);

#define OTP_WR_CMD_CODE_LEN 0x1b8
#define OTP_WR_CMD_CODE_CRC 0x9a0d

const unsigned char otp_wr_cmd_code[] = {
    0x01, 0x38, 0xfd, 0xd1, 0x70, 0x47, 0x00, 0x00, 0xf7, 0xb5, 0x81, 0xb0, 0x00, 0x21, 0x00, 0x91, 0x03, 0x21, 0x89,
    0x06, 0x0b, 0x6a, 0x5b, 0x08, 0x5b, 0x00, 0x0b, 0x62, 0x0b, 0x6a, 0x02, 0x24, 0x23, 0x43, 0x0b, 0x62, 0x0b, 0x6a,
    0x9b, 0x07, 0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x8e, 0x62, 0x01, 0x23, 0xcb, 0x60, 0x35, 0x24, 0x4c, 0x60, 0x0b,
    0x61, 0x8c, 0x6a, 0xe4, 0x05, 0xfc, 0xd5, 0x8e, 0x62, 0x8c, 0x69, 0x01, 0x23, 0xe4, 0xb2, 0xcb, 0x60, 0x05, 0x25,
    0x4d, 0x60, 0x0b, 0x61, 0x8b, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0xff, 0x26, 0x01, 0x36, 0x03, 0x23, 0x9b, 0x06, 0x9e,
    0x62, 0x9b, 0x69, 0x21, 0x02, 0x19, 0x43, 0xc9, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x73, 0xe0, 0x00, 0x21, 0x8c, 0x46,
    0x00, 0x2a, 0x71, 0xd0, 0x02, 0x9b, 0x11, 0x04, 0x63, 0x44, 0x9e, 0x46, 0x09, 0x0e, 0x03, 0x06, 0x1b, 0x0e, 0x6b,
    0xd0, 0xff, 0x21, 0xc3, 0xb2, 0x01, 0x31, 0xcb, 0x1a, 0x9a, 0x42, 0x00, 0xd8, 0x13, 0x46, 0x06, 0x24, 0x61, 0x06,
    0x4c, 0x60, 0x01, 0x24, 0x0c, 0x61, 0x8c, 0x6a, 0xe4, 0x05, 0xfc, 0xd5, 0xff, 0x24, 0x01, 0x34, 0x03, 0x21, 0x89,
    0x06, 0x8c, 0x62, 0x4c, 0x69, 0xff, 0x25, 0x08, 0x35, 0xac, 0x43, 0x4c, 0x61, 0x4c, 0x69, 0x04, 0x25, 0x2c, 0x43,
    0x4c, 0x61, 0x04, 0x02, 0x42, 0x34, 0x4c, 0x60, 0xcb, 0x60, 0x00, 0x25, 0x00, 0x2b, 0x16, 0xd9, 0x71, 0x46, 0x4f,
    0x19, 0x3e, 0x78, 0xfc, 0x78, 0x31, 0x46, 0x7e, 0x78, 0x24, 0x06, 0x36, 0x02, 0x31, 0x43, 0xbe, 0x78, 0x36, 0x04,
    0x31, 0x43, 0x21, 0x43, 0x09, 0x02, 0xfc, 0x78, 0x09, 0x0a, 0x24, 0x06, 0x21, 0x43, 0x2f, 0x4c, 0x21, 0x60, 0x2d,
    0x1d, 0x9d, 0x42, 0xe8, 0xd3, 0x01, 0x25, 0x03, 0x24, 0xa4, 0x06, 0x25, 0x61, 0xa1, 0x6a, 0xc9, 0x05, 0xfc, 0xd5,
    0xff, 0x26, 0x01, 0x36, 0xa6, 0x62, 0x00, 0x21, 0x05, 0x27, 0x01, 0x26, 0x03, 0x24, 0xa4, 0x06, 0xe6, 0x60, 0x35,
    0x25, 0x65, 0x60, 0x26, 0x61, 0xa5, 0x6a, 0xed, 0x05, 0xfc, 0xd5, 0xff, 0x25, 0x01, 0x35, 0xa5, 0x62, 0xa5, 0x69,
    0xe6, 0x60, 0xed, 0xb2, 0x67, 0x60, 0x26, 0x61, 0xa6, 0x6a, 0xf6, 0x05, 0xfc, 0xd5, 0xff, 0x26, 0x01, 0x36, 0xa6,
    0x62, 0xa4, 0x69, 0x2d, 0x02, 0x25, 0x43, 0xec, 0x07, 0x0e, 0xd0, 0x19, 0x4c, 0xa1, 0x42, 0x09, 0xd9, 0x02, 0x20,
    0x00, 0x90, 0x14, 0xe0, 0x0e, 0xe0, 0xff, 0xe7, 0x00, 0x29, 0x97, 0xd0, 0xff, 0x23, 0x01, 0x33, 0x95, 0xe7, 0x49,
    0x1c, 0xd3, 0xe7, 0x61, 0x46, 0xc9, 0x18, 0xc0, 0x18, 0x8c, 0x46, 0xd2, 0x1a, 0x00, 0xd0, 0x7d, 0xe7, 0xff, 0x20,
    0x01, 0x30, 0x03, 0x21, 0x89, 0x06, 0x88, 0x62, 0x03, 0x20, 0x80, 0x06, 0x41, 0x69, 0xff, 0x22, 0x08, 0x32, 0x91,
    0x43, 0x41, 0x61, 0x42, 0x69, 0x01, 0x21, 0x0a, 0x43, 0x42, 0x61, 0x02, 0x6a, 0x92, 0x08, 0x92, 0x00, 0x02, 0x62,
    0x02, 0x6a, 0x0a, 0x43, 0x02, 0x62, 0x00, 0x98, 0x04, 0xb0, 0xf0, 0xbd, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0c, 0x09,
    0x3d, 0x00, 0x00,
};

/**
 * @brief Write mutable length data to flash with ble schedule on.
 * @param[in] addr Security Registers Address.
 * @param[in] p_data data to write.
 * @param[in] len data len. 256Byte max
 * @return ReturnMsg.
 */
uint32_t OTPTrim_Write(uint32_t addr, uint8_t *p_data, uint32_t len)
{
    uint32_t error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    if (OTP_ADDRESS_CHECK(addr))
    {
        uint32_t ramcode[OTP_WR_CMD_CODE_LEN / 4 + 1];
        otp_wr_cmd_func_t otp_write_cmd_func = (otp_wr_cmd_func_t)((uint8_t *)&ramcode[0] + 0x09);
        memcpy((void *)ramcode, (const void *)otp_wr_cmd_code, OTP_WR_CMD_CODE_LEN);
        error = (*otp_write_cmd_func)(addr, p_data, len);
    }
    GLOBAL_INT_RESTORE();
    return error;
}

// Lock OTP
typedef ReturnMsg (*otp_lock_cmd_func_t)(uint32_t addr);

#define OTP_LOCK_CMD_CODE_LEN 0xf0
#define OTP_LOCK_CMD_CODE_CRC 0x1176

const unsigned char otp_lock_cmd_code[] = {
    0xf0, 0xb4, 0x04, 0x46, 0x00, 0x20, 0x03, 0x22, 0x92, 0x06, 0x11, 0x6a, 0x49, 0x08, 0x49, 0x00, 0x11, 0x62, 0x11,
    0x6a, 0x02, 0x23, 0x19, 0x43, 0x11, 0x62, 0x11, 0x6a, 0x89, 0x07, 0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x96, 0x62,
    0x01, 0x25, 0xd5, 0x60, 0x35, 0x27, 0x57, 0x60, 0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x91,
    0x69, 0xd5, 0x60, 0xc9, 0xb2, 0x05, 0x23, 0x53, 0x60, 0x15, 0x61, 0x93, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62,
    0x93, 0x69, 0x09, 0x02, 0xdb, 0xb2, 0x19, 0x43, 0xcb, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x33, 0xe0, 0x24, 0x0b, 0x09,
    0x0a, 0x2b, 0x46, 0xa4, 0x1c, 0xa3, 0x40, 0x0b, 0x43, 0x99, 0xb2, 0x06, 0x23, 0x53, 0x60, 0x15, 0x61, 0x93, 0x6a,
    0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0xc9, 0xb2, 0xd1, 0x61, 0x31, 0x21, 0x51, 0x60, 0xd5, 0x60, 0x15, 0x61, 0x91,
    0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x00, 0x21, 0x05, 0x24, 0xd5, 0x60, 0x35, 0x23, 0x53, 0x60, 0x15, 0x61,
    0x93, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x93, 0x69, 0xd5, 0x60, 0xdb, 0xb2, 0x54, 0x60, 0x15, 0x61, 0x97,
    0x6a, 0xff, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x97, 0x69, 0x1b, 0x02, 0x3b, 0x43, 0xdb, 0x07, 0x03, 0xd0, 0x0b, 0x4b,
    0x99, 0x42, 0x11, 0xd9, 0x02, 0x20, 0x51, 0x69, 0xff, 0x23, 0x08, 0x33, 0x99, 0x43, 0x51, 0x61, 0x51, 0x69, 0x29,
    0x43, 0x51, 0x61, 0x11, 0x6a, 0x89, 0x08, 0x89, 0x00, 0x11, 0x62, 0x11, 0x6a, 0x29, 0x43, 0x11, 0x62, 0xf0, 0xbc,
    0x70, 0x47, 0x49, 0x1c, 0xd2, 0xe7, 0x00, 0x00, 0x73, 0xcb, 0x00, 0x00,
};

/**
 * @brief Lock Security Registers.
 * @param[in] addr Security Registers Address.
 * @return ReturnMsg.
 */
uint32_t OTPTrim_Lock(uint32_t addr)
{
    uint32_t error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    if (OTP_ADDRESS_CHECK(addr))
    {
        uint32_t ramcode[OTP_LOCK_CMD_CODE_LEN / 4 + 1];
        otp_lock_cmd_func_t otp_lock_cmd_func = (otp_lock_cmd_func_t)((uint8_t *)&ramcode[0] + 0x01);
        memcpy((void *)ramcode, (const void *)otp_lock_cmd_code, OTP_LOCK_CMD_CODE_LEN);
        error = (*otp_lock_cmd_func)(OTP_ADDRESS_TO_SECTOR(addr));
    }
    GLOBAL_INT_RESTORE();
    return error;
}

// Query OTP Lock Status
typedef ReturnMsg (*otp_query_cmd_func_t)(uint32_t addr, uint8_t *result);

#define OTP_QUERY_CMD_CODE_LEN 0x94
#define OTP_QUERY_CMD_CODE_CRC 0x65f0

const unsigned char otp_query_cmd_code[] = {
    0xf0, 0xb4, 0x07, 0x46, 0x00, 0x20, 0x03, 0x22, 0x92, 0x06, 0x13, 0x6a, 0x5b, 0x08, 0x5b, 0x00, 0x13, 0x62, 0x13,
    0x6a, 0x02, 0x24, 0x23, 0x43, 0x13, 0x62, 0x13, 0x6a, 0x9b, 0x07, 0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x96, 0x62,
    0x01, 0x24, 0xd4, 0x60, 0x35, 0x23, 0x53, 0x60, 0x14, 0x61, 0x93, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x93,
    0x69, 0xd4, 0x60, 0xdb, 0xb2, 0x05, 0x25, 0x55, 0x60, 0x14, 0x61, 0x95, 0x6a, 0xed, 0x05, 0xfc, 0xd5, 0x96, 0x62,
    0x95, 0x69, 0x1b, 0x02, 0xed, 0xb2, 0x2b, 0x43, 0xdd, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x0a, 0xe0, 0x3d, 0x0b, 0x1b,
    0x0a, 0x26, 0x46, 0xad, 0x1c, 0xae, 0x40, 0x1e, 0x42, 0x01, 0xd0, 0x0c, 0x70, 0x01, 0xe0, 0x00, 0x23, 0x0b, 0x70,
    0x51, 0x69, 0xff, 0x23, 0x08, 0x33, 0x99, 0x43, 0x51, 0x61, 0x51, 0x69, 0x21, 0x43, 0x51, 0x61, 0x11, 0x6a, 0x89,
    0x08, 0x89, 0x00, 0x11, 0x62, 0x11, 0x6a, 0x21, 0x43, 0x11, 0x62, 0xf0, 0xbc, 0x70, 0x47,
};
/**
 * @brief Query Lock Security Registers.
 * @param[in] addr Security Registers Address.
 * @param[out] addr Security Registers Status, 0:unlock, 1:locked.
 * @return ReturnMsg.
 */
uint32_t OTPTrim_Query(uint32_t addr, uint8_t *status)
{
    uint32_t error = FlashAddressInvalid;
    GLOBAL_INT_DISABLE();
    if (OTP_ADDRESS_CHECK(addr))
    {
        uint32_t ramcode[OTP_QUERY_CMD_CODE_LEN / 4 + 1];
        otp_query_cmd_func_t otp_query_cmd_func = (otp_query_cmd_func_t)((uint8_t *)&ramcode[0] + 0x01);
        memcpy((void *)ramcode, (const void *)otp_query_cmd_code, OTP_QUERY_CMD_CODE_LEN);
        error = (*otp_query_cmd_func)(OTP_ADDRESS_TO_SECTOR(addr), status);
    }
    GLOBAL_INT_RESTORE();
    return error;
}

// Chip Erase
typedef ReturnMsg (*chip_erase_cmd_func_t)(void);
#define CHIP_ERASE_CMD_CODE_LEN 0xd4
#define CHIP_ERASE_CMD_CODE_CRC 0x9a4a

const unsigned char chip_erase_cmd_code[] = {
    0xf0, 0xb4, 0x00, 0x20, 0x03, 0x22, 0x92, 0x06, 0x11, 0x6a, 0x49, 0x08, 0x49, 0x00, 0x11, 0x62, 0x11, 0x6a,
    0x02, 0x23, 0x19, 0x43, 0x11, 0x62, 0x11, 0x6a, 0x89, 0x07, 0xfc, 0xd4, 0xff, 0x26, 0x01, 0x36, 0x96, 0x62,
    0x01, 0x25, 0xd5, 0x60, 0x35, 0x23, 0x53, 0x60, 0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62,
    0x91, 0x69, 0xd5, 0x60, 0xc9, 0xb2, 0x05, 0x24, 0x54, 0x60, 0x15, 0x61, 0x97, 0x6a, 0xff, 0x05, 0xfc, 0xd5,
    0x96, 0x62, 0x97, 0x69, 0x09, 0x02, 0x39, 0x43, 0xc9, 0x07, 0x01, 0xd0, 0x03, 0x20, 0x28, 0xe0, 0x06, 0x21,
    0x51, 0x60, 0x15, 0x61, 0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0xc7, 0x21, 0x51, 0x60, 0x15, 0x61,
    0x91, 0x6a, 0xc9, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x00, 0x21, 0xd5, 0x60, 0x35, 0x23, 0x53, 0x60, 0x15, 0x61,
    0x93, 0x6a, 0xdb, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x93, 0x69, 0xd5, 0x60, 0xdb, 0xb2, 0x54, 0x60, 0x15, 0x61,
    0x97, 0x6a, 0xff, 0x05, 0xfc, 0xd5, 0x96, 0x62, 0x97, 0x69, 0x1b, 0x02, 0x3b, 0x43, 0xdb, 0x07, 0x03, 0xd0,
    0x0b, 0x4b, 0x99, 0x42, 0x11, 0xd9, 0x02, 0x20, 0x51, 0x69, 0xff, 0x23, 0x08, 0x33, 0x99, 0x43, 0x51, 0x61,
    0x51, 0x69, 0x29, 0x43, 0x51, 0x61, 0x11, 0x6a, 0x89, 0x08, 0x89, 0x00, 0x11, 0x62, 0x11, 0x6a, 0x29, 0x43,
    0x11, 0x62, 0xf0, 0xbc, 0x70, 0x47, 0x49, 0x1c, 0xd2, 0xe7, 0xcd, 0x96, 0x20, 0x00,
};

/**
 * @brief Chip Erase
 * @return ReturnMsg.
 */
uint32_t Qflash_Chip_Erase(void)
{
    uint32_t error = FlashIsBusy;
    GLOBAL_INT_DISABLE();
    uint32_t ramcode[CHIP_ERASE_CMD_CODE_LEN / 4 + 1];
    chip_erase_cmd_func_t chip_erase_cmd_func = (chip_erase_cmd_func_t)((uint8_t *)&ramcode[0] + 0x01);
    memcpy((void *)ramcode, (const void *)chip_erase_cmd_code, CHIP_ERASE_CMD_CODE_LEN);
    error = (*chip_erase_cmd_func)();
    GLOBAL_INT_RESTORE();
    return error;
}

#endif

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
